信号量和条件变量的关系是什么?

您所在的位置:网站首页 condition variable 信号量和条件变量的关系是什么?

信号量和条件变量的关系是什么?

#信号量和条件变量的关系是什么?| 来源: 网络整理| 查看: 265

你理解的是对的。信号量和互斥体确实可以解决大部分多线程并发中的问题。但是可以解决并不代表它就是最合适的解决方案。每种同步对象都有它特定的适用场景。

多线程并发中最基本的2个需求,一个是“同步”,一个是“等待”。

“同步”理解起来很容易,就是2个或者多个线程会同时访问同一个共享资源,这个时候就需要同步。互斥体mutex就适用于这个场景。

“等待”最典型的场景就是“生产者/消费者”模式。如果只有互斥体mutex这种处理“同步”的设施,我们会如何处理“生产者/消费者”模式呢?很容易想到的就是“轮询”,即poll。就是每个固定的时间间隔,就检查一次是否有“消息”进来了,可以“消费”了。如果有,就“消费”;如果没有,就sleep一段时间,然后时间到了,再查询一次是否有“消息”进来了。“轮询”的缺点显而易见。如果查询间隔太短,就做太多无用功,导致程序性能下降;如果查询间隔太长,则当有“消息”进来了,可以“消费”的时候,不能及时的响应,影响用户体验。

那么如何处理“生产者/消费者”模式最合适呢?条件变量(condition variable)就是最合适的选择。它需要配合互斥体mutex一起使用。以下以线程安全的“同步队列”为例来看一下条件变量的使用。

template class Sync_queue { public: void put(const T& val); void put(T&& val); void get(T& val); private: mutex mtx; condition_variable cond; list q; };

“生产者”线程可以调用它的put方法。如下:

template void Sync_queue::put(const T& val) { lock_guard lck(mtx); q.push_back(val); cond.notify_one(); }

“消费者”线程可以调用它的get方法。如下:

template void Sync_queue::get(T& val) { unique_lock lck(mtx); cond.wait(lck,[this]{ return !q.empty(); }); val=q.front(); q.pop_front(); }

很明显,相比“轮询”的方法,使用“条件变量”的方法不知道高的哪里去了。

需要说明的是,这里的“条件”可以由程序员任意指定。即,!q.empty()?

实际上,信号量也是用来处理“等待”的。但是它有自己的特定使用场景。典型的,可以把“信号量”理解为,“可用的共享资源数”。以停车场为例,停车场的“剩余车位数”即是对应到“信号量”的value的。即:

int sem_init(sem_t *sem, int pshared, unsigned int value);

如果value是0,就代表已经没有剩余车位了。那么,想进停车场的车主,就需要在入口处“等待”。直到有车开走了,又有空余车位了,才可以proceed。即从“信号量”的“等待”中返回。

可见,确实也可以使用“信号量”+“互斥体”来解决“生产者/消费者”模式的问题。但是,显然用“条件变量”更合适。

计算机技术是一点点发展到现在的,所以有些东西在功能上面有重叠的地方是很正常的。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3